<script>
/* 这是一个导航组件：
 * 自动获取路由生成导航功能，该组件只会初始化一次
 * 会自动在SessionStorage生成一个名为NowPage的key，用来记录当前是那个页面
 * 在SessionStorage置入一个名为OpenDebug的key，值为true，即可开启全局Debug
 */

/* 关于Feature这个路由指向用的参数：
 * 首先，这个值接收一个数组，依靠name对象来识别
 * 数组按照路由级来排，示例：[0级路由，1级路由，2级路由]
 * 由于是循环在处理，所以无法拿到同级其他路由下的子路由
 * 如果想拿其他路由下的子路由用另一个参数就行了，只是这个参数比FeatureS优先度要高
 * 如果空值则默认拿整个一级路由
 * 拿到路由后会自动寻找路由中的meta对象，没有的自己创建一个
 * 会对meta对象进行处理，没有meta或meta不满足条件的一律不会生成导航按钮
 * 在meta对象中你需要写入以下对象
 * PageOne => 用于激活选中CSS样式，如果你将一些同级路由归类到同一个导航按钮的话，则为它们设定相同的值
 * Show => 简单的控制是否要将这个路由作为一个导航按钮显示，true以外的值一律隐藏
 * PageIon => 这个是作为导航按钮上的图标，不要图标的话，请设置为空，但是一定要有这个对象
 * Purview => 这是个排除项，当和父页面传递进来的Purview相同时，则屏蔽这个路由
 */

/* 关于FeatureS这个复数路由指向用的参数：
 * 它和Feature的特性完全相同
 * 数组的写法有所不同，示例如下
 * [[0级路由A，A的1级路由，A的2级路由],[0级路由B，B的1级路由，B的2级路由]]
 */

export default {
  // 控制组件用的参数
  props: {
    Size: null, // 按钮内文字大小
    BgColor: null, // 整个导航的背景颜色，支持16进制，支持透明
    TxColor: null, // 文字颜色，默认会自动根据背景色来选择黑白
    TnColor: null, // 文字被选中后的颜色，没有的默认使用#409eff
    Feature: null, // 指向，看上面的说明
    FeatureS: null, // 复数指向
    Purview: null, // 要排除的内容
    DeBug: null, // 调试模式，true以外的值一律为禁用
    DeBugId: null, // 调试模式ID，可有可无
    IconFont: null // 将图标作为字体加载用的css
  },

  // 主要变量
  data: () => ({
    SIZE: 0, // 默认的按钮文字大小
    WIDTH: 0, // 按钮的宽度，由JS计算获得
    HEIGHT: 0, // 按钮的宽度，由JS计算获得
    ROUTER: null, // 获取到的路由数据
    RCOLOR: null, // 与背景相反的颜色
    TCOLOR: null, // 配置文字颜色
    NCOLOR: null, // 选中后的文字颜色
    BGCOLOR: "#444444", // 背景颜色
    NOWPAGE: window.sessionStorage.getItem("NowPageOwn"), // 记录当前是哪个页面
    TERMA: new RegExp(/^#([0-9a-fA-F]{6})$/), // 颜色匹配正则（6位）
    TERMB: new RegExp(/^#([0-9a-fA-F]{8})$/) // 颜色匹配正则（8位）
  }),

  // 渲染前执行
  created() {
    console.time("组件完成渲染用时："); // 记录时间F

    this.SIZE = this.Size || 0.65; // 获取文字大小，默认0.65vw

    // 处理用户配置的背景颜色
    if (this.TERMA.test(this.BgColor) || this.TERMB.test(this.BgColor)) {
      this.BGCOLOR = this.Color;
    }

    // 自动通过反色的方法生成选中后的颜色
    this.RCOLOR = this.ColorReverse(this.BGCOLOR);

    // 处理用户配置文字颜色
    if (this.TERMA.test(this.TxColor) || this.TERMB.test(this.TxColor)) {
      this.TCOLOR = this.TxColor;
    } else {
      this.TCOLOR = this.Tone(this.BGCOLOR) ? "#000000" : "#ffffff"; // 通过色调来判断是黑字还是白字
    }

    // 处理用户配置文字颜色
    if (this.TERMA.test(this.TnColor) || this.TERMB.test(this.TnColor)) {
      this.NCOLOR = this.TnColor;
    } else {
      this.NCOLOR = "#409eff"; // 通过色调来判断是黑字还是白字
    }

    this.GetRouter();
  },

  // 渲染后执行
  mounted() {
    let V = document.body.clientWidth / 100; // 获取当前窗口1vw等于多少px
    let W = this.$refs.KL.offsetWidth / 10; // 获取被渲染后的内容宽度（px单位）
    let H = this.$refs.KL.offsetHeight / 10; // 获取被渲染后的内容宽度（px单位）
    this.WIDTH = W / V; // 将px单位转换成vw单位
    this.HEIGHT = H / V; // 将px单位转换成vw单位

    // 通过模拟用户操作来防止未出现子页面
    if (this.NOWPAGE) {
      // 向父页面传回路由name
      this.$emit(
        "Click",
        this.ROUTER.find(E => E.PageOwn == this.NOWPAGE).Name
      );
    } else {
      this.Click(0);
    }

    this.BugLog(); // 调用调试输出
  },

  methods: {
    // 反色转换
    ColorReverse(E) {
      let A = "0x" + E.replace(/#/g, ""); // 将颜色代码转换成内存代码
      let B = "000000" + (0xffffff - A).toString(16); // 16进制相减，并加上前6位防止溢出
      let C = B.substring(B.length - 6, B.length); // 去除溢出部分
      return `#${C}88`; // 返回正确的颜色代码并加上50%的透明度
    },

    // 判断颜色深浅
    Tone(E) {
      let A = "0x" + E.replace(/#/g, ""); // 将颜色代码转换成内存代码
      return A > 0x888888; // false代表深色，true代表浅色
    },

    // 获取路由参数
    GetRouter() {
      if (this.Feature != undefined && this.Feature.length > 0) {
        // 识别传入数组来处理路由指向
        this.EasyFeature();
      } else if (this.FeatureS != undefined && this.FeatureS.length > 0) {
        // 当用户有复数路由指向时
        this.EasyFeatureS();
      } else {
        // 没有指定路由指向时的处理
        this.ROUTER = this.MapGo(this.$router.options.routes);
      }
    },

    // 返回最终值（按照我个人习惯写出来的数据处理）
    MapGo(E) {
      return E.map(R => {
        if (R.meta) {
          if (R.meta.Show == true) {
            return {
              Name: R.name || null, // 跳转路由用的，我并不喜欢用path
              PageOwn: R.meta.PageOwn || `页面${i}`,
              PageIon: R.meta.PageIon || "",
              Purview: R.meta.Purview || "",
              BgColor: null, // 调整背景颜色
              TxColor: this.TCOLOR // 调整文字颜色
            };
          }
        }
      }).filter(R => R != undefined);
    },

    // 路由处理
    EasyFeature() {
      var R = this.$router.options.routes; // 提取出整个一级路由

      try {
        // 循环处理指向
        this.Feature.forEach((E, I) => {
          R = R.find(L => L.name == E); // 复写拿到的路由表

          // 检测循环错误
          if (R == undefined) {
            throw new Error(`导航组件错误，${I}级路由下找不到${E}`);
          } else if (R.children == undefined) {
            throw new Error(`导航组件错误，${I}级路${E}下面没有子路由`);
          } else if (R.children.length < 1) {
            throw new Error(`导航组件错误，${I}级路${E}下面没有子路由`);
          } else {
            R = R.children;
          }
        });

        this.ROUTER = this.MapGo(R);
      } catch (Err) {
        console.error(Err); // 输出报错
      }
    },

    // 路由处理（复数模式）
    EasyFeatureS() {
      var R = this.$router.options.routes; // 提取出整个一级路由

      try {
        // 循环处理指向
        this.FeatureS.map(Ex => {
          Ex.forEach((E, I) => {
            R = R.find(L => L.name == E); // 复写拿到的路由表

            // 检测循环错误
            if (R == undefined) {
              throw new Error(`导航组件错误，${I}级路由下找不到${E}`);
            } else if (R.children == undefined) {
              throw new Error(`导航组件错误，${I}级路${E}下面没有子路由`);
            } else if (R.children.length < 1) {
              throw new Error(`导航组件错误，${I}级路${E}下面没有子路由`);
            } else {
              R = R.children;
            }
          });
        });

        this.ROUTER = this.MapGo(R);
      } catch (Err) {
        console.error(Err); // 输出报错
      }
    },

    // 鼠标悬停时触发
    Enter(I) {
      this.ROUTER[I].BgColor = this.RCOLOR;
    },

    // 鼠标离开时触发
    Leave(I) {
      this.ROUTER[I].BgColor = null;
    },

    // 处理按钮的点击事件
    Click(I) {
      this.NOWPAGE = this.ROUTER[I].PageOwn;
      window.sessionStorage.setItem("NowPageOwn", this.ROUTER[I].PageOwn);
      this.$emit("Click", this.ROUTER[I].Name); // 将点击事件返回给父页面，传回路由里的name
    },

    // 汇报bug
    BugLog() {
      if (
        this.DeBug == true ||
        window.sessionStorage.getItem("OpenDebug") == "true"
      ) {
        console.group(
          `来自导航组件的日志：${
            this.DeBugId != undefined ? "（ID:" + this.DeBugId + ")" : ""
          }`
        );

        console.table(this.ROUTER, ["Name", "PageOwn", "PageIon", "Purview"]);
        console.table([
          { Name: "当前激活的项", Val: this.NOWPAGE },
          { Name: "背景颜色", Val: this.BGCOLOR },
          { Name: "鼠标悬浮颜色", Val: this.RCOLOR },
          { Name: "字体大小", Val: this.SIZE + "vw" }
        ]);
        console.timeEnd("组件完成渲染用时：");

        console.groupEnd();
      }
    }
  }
};
</script>

<template>
  <div class="BackE116E861D9FDF08F" :style="{backgroundColor:BGCOLOR}">
    <div class="BasisE116E861D9FDF08F" :style="{width:WIDTH+'vw',height:HEIGHT+'vw'}">
      <div class="Enlarge3486E67B6753E98F" ref="KL">
        <div
          v-for="(R,I) in ROUTER"
          :key="I"
          :style="{padding:SIZE*10+'vw',backgroundColor:R.BgColor}"
          @mouseenter="Enter(I)"
          @mouseleave="Leave(I)"
          @click="Click(I)"
        >
          <button
            class="Button3486E67B6753E98F"
            :class="[IconFont,R.PageIon]"
            :style="{fontSize:SIZE*10+'vw',color:NOWPAGE==R.PageOwn?NCOLOR:R.TxColor}"
          >&ensp;{{R.PageOwn}}</button>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.BackE116E861D9FDF08F {
  /* 控制最外层框的样式 */
  height: 100%;
}

.BasisE116E861D9FDF08F {
  /* 导航背景的基础样式 */
  transition-property: none !important;
  float: left;
}

.Enlarge3486E67B6753E98F {
  /* 强行把按钮内文字部分缩小10倍 */
  transform: translate(-50%, -50%) scale(0.1);
  white-space: nowrap;
  position: relative;
  float: left;
  left: 50%;
  top: 50%;
}

.Button3486E67B6753E98F {
  background-color: transparent;
  position: relative;
  line-height: 1;
  border: none;
  padding: 0;
}
</style>